
#include <BFile>
#include <BEntry>
#include <BFolder>
#include <BStyle>
#include <BCursor>

#include <BReadWrite>
#include <BLabel>
#include <BHBoxLayout>
#include <BVBoxLayout>
#include <BMessageBox>
#include <BHtmlWidget>
#include <BTextEdit>
#include <BSonDocument>
#include <BSystem>
#include <BApplication>

#include "Settings.h"
#include "StyleEditDialog.h"
#include "ExtentionEditor.h"
#include "TextEditor.h"
#include "HtmlFormat.h"
#include "InitFormat.h"
#include "ScriptFormat.h"
#include "SonFormat.h"
#include "StyleFormat.h"
#include "XmlFormat.h"
#include "YamlFormat.h"
#include "MainWindow.h"

MainWindow::MainWindow()
{
	_searchDialog = new SearchDialog(this);
	_fileDialog = new BFileDialog(this);

	initMenuBar();

	BHBoxLayout* toolLayout = new BHBoxLayout();
	{
		_openPathButton = new BButton(_fileMenu->action("Open folder"));
		_openPathButton->setForm(Form_IconAlone);

		_openFileButton = new BButton(_fileMenu->action("Open file"));
		_openFileButton->setForm(Form_IconAlone);

		_newFileButton = new BButton(_fileMenu->action("New file"));
		_newFileButton->setForm(Form_IconAlone);

		_saveButton = new BButton(_fileMenu->action("Save file"));
		_saveButton->setForm(Form_IconAlone);

		_saveAllButton = new BButton(_fileMenu->action("Save All"));
		_saveAllButton->setForm(Form_IconAlone);

		_removeButton = new BButton(_fileMenu->action("Remove"));
		_removeButton->setForm(Form_IconAlone);

		_clearButton = new BButton(_fileMenu->action("Clear"));
		_clearButton->setForm(Form_IconAlone);

		_searchButton = new BButton(_editMenu->action("Search"));
		_searchButton->setForm(Form_IconAlone);

		_undoButton = new BButton(_editMenu->action("Undo"));
		_undoButton->setForm(Form_IconAlone);

		_redoButton = new BButton(_editMenu->action("Redo"));
		_redoButton->setForm(Form_IconAlone);

		_stackListButton = new BButton(Graph_Arrow_Down_Fill);
		_stackListButton->setForm(Form_IconOnly);
		_stackListButton->setCheckable(true);
		_stackListWidget = new OperaStackDialog(this);
		_stackListWidget->hide();

		toolLayout->addWidget(_openPathButton);
		toolLayout->addWidget(_openFileButton);
		toolLayout->addWidget(_newFileButton);
		toolLayout->addWidget(_saveButton);
		toolLayout->addWidget(_saveAllButton);
		toolLayout->addWidget(_removeButton);
		toolLayout->addWidget(_clearButton);
		toolLayout->addWidget(_searchButton);
		toolLayout->addSpacer(10);
		toolLayout->addWidget(_undoButton);
		toolLayout->addWidget(_redoButton);
		toolLayout->addWidget(_stackListButton);
		toolLayout->addSpring();
	}

	_workspace = new BTreeWidget("Workspace");
	_workspace->setSelectMode(Select_Single);

	BVBoxLayout* rightLayout = new BVBoxLayout();
	rightLayout->setSplitable(true);
	rightLayout->setSpacing(4);
	{
		_tabWidget = new BTabWidget();

		_searchBoard = new BTreeWidget();
		_searchBoard->hide();
		rightLayout->addWidget(_tabWidget, 4);
		rightLayout->addWidget(_searchBoard);
	}

	BHBoxLayout* splitLayout = new BHBoxLayout();
	splitLayout->setSplitable(true);
	splitLayout->setSpacing(6);
	splitLayout->addWidget(_workspace);
	splitLayout->addLayout(rightLayout, 4);

	BVBoxLayout* layout = new BVBoxLayout(this);
	layout->addWidget(_menuBar, 0);
	layout->addLayout(toolLayout, 0);
	layout->addLayout(splitLayout);

	connect(_workspace, Signal_ItemDoubleClicked, &MainWindow::slotTreeItemDoubleClicked);
	connect(_workspace, Signal_ItemRightClicked, &MainWindow::slotTreeItemRightClicked);
	connect(_workspace, Signal_TitleChanged, &MainWindow::slotWorkspaceTitleChanged);
	connect(_workspace, Signal_Styled, &MainWindow::slotWorkspaceStyled);

	connect(_tabWidget, Signal_CurrentChanged, &MainWindow::slotTabCurrentChanged);
	connect(_tabWidget, Signal_TabClosing, &MainWindow::slotTabClosing);
	connect(_tabWidget, Signal_TabClicked, &MainWindow::slotTabClicked);
	connect(_tabWidget, Signal_TabRightClicked, &MainWindow::slotTabRightClicked);

	connect(_removeButton, Signal_Clicked, &MainWindow::slotRemoveButtonClicked);
	connect(_clearButton, Signal_Clicked, &MainWindow::slotClearButtonClicked);
	connect(_stackListButton, Signal_Toggled, &MainWindow::slotStackListButtonToggled);

	_searchDialog->setProperty("workspace", _workspace);
	_searchDialog->setProperty("editspace", _tabWidget);
	_searchDialog->setProperty("results", _searchBoard);

	connect(_searchDialog, "search-finished", &MainWindow::slotSearchFinished);
	connect(_searchDialog, Signal_Hide, &MainWindow::slotSearchDialogHide);
	connect(_searchBoard, Signal_ItemDoubleClicked, &MainWindow::slotResultItemDoubleClicked);

	connect("edit-file", &MainWindow::slotEditFile);

	loadConfig("./data/config/document.son");
	updateToolBar();

	if (Settings* settings = BApplication::property("settings"))
	{
		_viewMenu->findAction("show-tabs")->setChecked(settings->showTabs());
		_viewMenu->findAction("show-spaces")->setChecked(settings->showSpaces());
		_viewMenu->findAction("show-returns")->setChecked(settings->showReturns());
		_viewMenu->findAction("show-linefeed")->setChecked(settings->showLinefeeds());
	}

}
MainWindow::~MainWindow()
{
	if (_saveButton->enabled() || _saveAllButton->enabled())
	{
		BSonNode* settingsNode = new BSonNode("settings");
		settingsNode->setFormat("{\n;\n}\n");
		for (int i = 0; i < _workspace->itemCount(); i++)
		{
			BTreeItem* item = _workspace->item(i);
			writeSonNode(item, settingsNode);
		}
		BSonDocument document;
		document.save("./data/config/document.son", settingsNode);
	}
	if (Settings* settings = BApplication::property("settings"))
	{
		if (settings->isDirty())
			settings->save();
	}
}

bool MainWindow::openFile(const BString& fileName)
{
	if (BWidget* widget = tabOfFile(fileName))
	{
		_tabWidget->setCurrent(widget);
		return true;
	}
	TextEditor* textEdit = new TextEditor();
	if (BTextFormat* format = createFormat(fileName.ext()))
	{
		textEdit->setTextFormat(format);
		format->setAsset(textEdit);
	}
	textEdit->setTitle(fileName.name());
	textEdit->setAsset(fileName);
	textEdit->setIcon(BSystem::EntryIcon(fileName));
	textEdit->loadFile(fileName);
	_tabWidget->addTab(textEdit, true);
	_tabWidget->setTabTips(textEdit, fileName);
	_tabWidget->setCurrent(textEdit);
	connect(textEdit, Signal_PropertyChanged, &MainWindow::slotEditorPropertyChanged);
	connect(textEdit, Signal_TextEdited, &MainWindow::slotTextEdited);
	connect(textEdit, Signal_Framed, &MainWindow::slotTextEditFramed);
	this->emit("file-opened", fileName);
	return true;
}

void MainWindow::initMenuBar()
{
	_menuBar = new BMenuBar();
	_menuBar->setSpacing(3);

	_fileMenu = new BMenu("File");
	{
		BAction* openPathAction = _fileMenu->addAction("Open folder");
		BAction* openFileAction = _fileMenu->addAction("Open file");
		BAction* newFileAction = _fileMenu->addAction("New file");
		BAction* saveFileAction = _fileMenu->addAction("Save file");
		BAction* saveAllAction = _fileMenu->addAction("Save All");
		BAction* saveAsAction = _fileMenu->addAction("Save As");
		BAction* removeAction = _fileMenu->addAction("Remove");
		BAction* clearAction = _fileMenu->addAction("Clear");

		openFileAction->setShortcut("ctrl+o");
		newFileAction->setShortcut("ctrl+N");
		saveFileAction->setShortcut("ctrl+ S");
		saveAllAction->setShortcut("ctrl+Shift+A");
		saveAsAction->setShortcut("ctrl+ Alt +A");
		removeAction->setShortcut("ctrl + Delete");
		clearAction->setShortcut("ctrl + Back");

		_fileMenu->addSeparator();
		BAction* quitAction = _fileMenu->addAction("Quit");
		connect(openPathAction, Signal_Triggered, &MainWindow::slotOpenPathActionTriggered);
		connect(openFileAction, Signal_Triggered, &MainWindow::slotOpenFileActionTriggered);
		connect(newFileAction, Signal_Triggered, &MainWindow::slotNewFileActionTriggered);
		connect(saveFileAction, Signal_Triggered, &MainWindow::slotSaveFileActionTriggered);
		connect(saveAllAction, Signal_Triggered, &MainWindow::slotSaveAllActionTriggered);
		connect(saveAsAction, Signal_Triggered, &MainWindow::slotSaveAsActionTriggered);
		connect(quitAction, Signal_Triggered, &MainWindow::slotQuitActionTriggered);
	}

	_editMenu = new BMenu("Edit");
	{
		BAction* undoAction = _editMenu->addAction("Undo");
		BAction* redoAction = _editMenu->addAction("Redo");
		_editMenu->addSeparator();
		BAction* searchAction = _editMenu->addAction("Search");
		searchAction->setCheckable(true);
		_editMenu->addSeparator();
		BAction* copyAction = _editMenu->addAction("Copy");
		BAction* cutAction = _editMenu->addAction("Cut");
		BAction* pasteAction = _editMenu->addAction("Paste");
		BAction* removeAction = _editMenu->addAction("Remove");

		undoAction->setShortcut("ctrl+z");
		redoAction->setShortcut("ctrl+shift+Z");
		searchAction->setShortcut("ctrl+F");
		copyAction->setShortcut("ctrl+c");
		cutAction->setShortcut("ctrl+x");
		pasteAction->setShortcut("ctrl+V");
		removeAction->setShortcut("delete");

		connect(undoAction, Signal_Triggered, &MainWindow::slotUndoActionTriggered);
		connect(redoAction, Signal_Triggered, &MainWindow::slotRedoActionTriggered);
		connect(searchAction, Signal_Triggered, &MainWindow::slotSearchActionTriggered);
		connect(copyAction, Signal_Triggered, &MainWindow::slotCopyActionTriggered);
		connect(cutAction, Signal_Triggered, &MainWindow::slotCutActionTriggered);
		connect(pasteAction, Signal_Triggered, &MainWindow::slotPasteActionTriggered);
		connect(removeAction, Signal_Triggered, &MainWindow::slotRemoveActionTriggered);

	}

	_viewMenu = new BMenu("View");
	{
		BMenu* showPunctMenu = _viewMenu->addMenu("Show Puncts");
		showPunctMenu->setName("show-puncts");
		{
			showPunctMenu->addAction("show-tabs")->setCheckable(true);
			showPunctMenu->addAction("show-spaces")->setCheckable(true);
			showPunctMenu->addAction("show-returns")->setCheckable(true);
			showPunctMenu->addAction("show-linefeed")->setCheckable(true);
		}
		BAction* sourceFontAction = _viewMenu->addAction("Source Font");
		BAction* scriptFontAction = _viewMenu->addAction("Script Font");
		connect(showPunctMenu, Signal_Triggered, &MainWindow::slotShowPunctMenuTriggered);
		connect(sourceFontAction, Signal_Triggered, &MainWindow::slotFontActionTriggered);
	}

	_toolMenu = new BMenu("Tool");
	{
		StyleEditDialog* stylesWidget = new StyleEditDialog(this);
		ExtentionEditor* extentionWidget = new ExtentionEditor(this);

		BAction* stylesAction = _toolMenu->addAction("Styles");
		BAction* extentionAction = _toolMenu->addAction("Extention");

		stylesAction->setAsset(stylesWidget);
		extentionAction->setAsset(extentionWidget);

		connect(_toolMenu, Signal_Triggered, &MainWindow::slotToolMenuTriggered);
	}

	_menuBar->addMenu(_fileMenu);
	_menuBar->addMenu(_editMenu);
	_menuBar->addMenu(_viewMenu);
	_menuBar->addMenu(_toolMenu);

	_listMenu = new BMenu(this);
	_listMenu->addAction("open");
	_listMenu->addAction("fresh");
	_listMenu->addAction("check");

	_pageMenu = new BMenu(this);
	//_pageMenu->setForm(Form_TextOnly);
	_pageMenu->addAction("open source")->setName("action-source");
	_pageMenu->addAction("show tree")->setName("action-tree");

	_tableMenu = new BMenu(this);
	_tableMenu->addAction("add row")->setName("action-add-row");
	_tableMenu->addAction("insert row")->setName("action-insert-row");
	_tableMenu->addAction("remove row")->setName("action-remove-row");
	_tableMenu->addAction("add column")->setName("action-add-column");
	_tableMenu->addAction("insert column")->setName("action-insert-column");
	_tableMenu->addAction("remove column")->setName("action-remove-column");

	_tabMenu = new BMenu(this);
	_tabMenu->addAction("Close Current Document")->setName("action-close-tab");
	_tabMenu->addAction("Close All Document")->setName("action-close-all-tab");
	_tabMenu->addAction("Close All Except Current")->setName("action-close-all-except-current");
	_tabMenu->addAction("Reload Content")->setName("reload-content");

	_useStyleMenu = _tabMenu->addMenu("use style");
	{
		_useStyleMenu->addAction("xml");
		_useStyleMenu->addAction("yaml");
		_useStyleMenu->addAction("son");
		_useStyleMenu->addAction("css");
		_useStyleMenu->addAction("bcs");
	}

	{
		BMenu* headMenu = new BMenu("head");
		headMenu->addAction("h1");
		headMenu->addAction("h2");
		headMenu->addAction("h3");
		headMenu->addAction("h4");
		headMenu->addAction("h5");
		headMenu->addAction("h6");

		BAction* pAction = new BAction("p");
		BAction* aAction = new BAction("a");
		BAction* textAction = new BAction("text");
		BAction* divAction = new BAction("div");
		BAction* tableAction = new BAction("table");
		BAction* imgAction = new BAction("img");

		BMenu* addMenu = new BMenu("Add");
		addMenu->setName("menu-add");
		addMenu->addMenu(headMenu);
		addMenu->addAction(pAction);
		addMenu->addAction(aAction);
		addMenu->addAction(textAction);
		addMenu->addAction(imgAction);
		addMenu->addAction(divAction);
		addMenu->addAction(tableAction);

		BMenu* prependMenu = new BMenu("Prepend");
		prependMenu->setName("menu-prepend");
		prependMenu->addMenu(headMenu);
		prependMenu->addAction(pAction);
		prependMenu->addAction(aAction);
		prependMenu->addAction(textAction);
		prependMenu->addAction(imgAction);
		prependMenu->addAction(divAction);
		prependMenu->addAction(tableAction);

		BMenu* appendMenu = new BMenu("Append");
		appendMenu->setName("menu-append");
		appendMenu->addMenu(headMenu);
		appendMenu->addAction(pAction);
		appendMenu->addAction(aAction);
		appendMenu->addAction(textAction);
		appendMenu->addAction(imgAction);
		appendMenu->addAction(divAction);
		appendMenu->addAction(tableAction);

		_pageMenu->addMenu(addMenu);
		_pageMenu->addMenu(prependMenu);
		_pageMenu->addMenu(appendMenu);

		connect(addMenu, Signal_Triggered, &MainWindow::slotMenuAddTrigger);
		connect(prependMenu, Signal_Triggered, &MainWindow::slotMenuPrependTrigger);
		connect(appendMenu, Signal_Triggered, &MainWindow::slotMenuAppendTrigger);
	}

	connect(_pageMenu, Signal_Triggered, &MainWindow::slotPageMenuTrigger);
	connect(_tableMenu, Signal_Triggered, &MainWindow::slotTableMenuTrigger);
	connect(_tabMenu, Signal_Triggered, &MainWindow::slotTabMenuTrigger);
	connect(_useStyleMenu, Signal_Triggered, &MainWindow::slotStyleMenuTriggered);

	connect(_fileMenu, Signal_Styled, &MainWindow::slotMenuStyled);
	connect(_editMenu, Signal_Styled, &MainWindow::slotMenuStyled);
	connect(_viewMenu, Signal_Styled, &MainWindow::slotMenuStyled);
	connect(_toolMenu, Signal_Styled, &MainWindow::slotMenuStyled);

}
bool MainWindow::loadConfig(const BString& fileName)
{
	BSonDocument document;
	if (BSonNode* settingsNode = document.load(fileName))
	{
		for (int i = 0; i < settingsNode->childCount(); i++)
		{
			BSonNode* child = settingsNode->child(i);
			BTreeItem* item = createTreeItem(child);
			_workspace->addItem(item);
		}
		return true;
	}
	return false;
}
BTextFormat* MainWindow::createFormat(const char* ext)
{
	BString formatName = ext;
	Settings* settings = BApplication::property("settings");
	const StringTable& extable = settings->extentionTable();
	for (int i = 0; i < extable.row(); i++)
	{
		if (extable(i, 0) == formatName)
		{
			formatName = extable(i, 1);
			break;
		}
	}

	if (formatName == "xml")
		return new XmlFormat();
	if (formatName == "yaml")
		return new YamlFormat();
	if (formatName == "son")
		return new SonFormat();
	if (formatName == "css")
		return new StyleFormat();
	if (formatName == "bcs")
		return new ScriptFormat;

	return 0;
}
BWidget* MainWindow::tabOfFile(const BString& fileName)
{
	for (int i = 0; i < _tabWidget->tabCount(); i++)
	{
		BWidget* widget = _tabWidget->tab(i);
		const BString& str = widget->asset();
		if (str == fileName)
			return widget;
	}
	return 0;
}
void MainWindow::signChanged(BWidget* widget, bool changed)
{
	const BString& title = widget->title();
	if (changed)
	{
		if (title.last() != '*')
		{
			widget->setTitle(title + '*');
		}
	}
	else
	{
		if (title.last() == '*')
		{
			widget->setTitle(title - '*');
		}
	}
}
BTreeItem* MainWindow::createTreeItem(BEntry* entry)
{
	BTreeItem* item = new BTreeItem(entry->name());
	item->setAsset(entry);
	item->setExpanded(false);
	if (entry->attrib() & Attrib_Folder)
	{
		BFolder folder(entry->path());
		if (folder.open())
		{
			for (int i = 0; i < folder.entryCount(); i++)
			{
				BEntry* entry = folder.entry(i);
				BTreeItem* child = createTreeItem(entry);
				item->addChild(child);
			}
		}
	}
	return item;
}
BTreeItem* MainWindow::createTreeItem(BSonNode* node)
{
	if (node->name() == "folder")
	{
		const BString& path = node->attrib("path");
		if (BEntry* entry = BEntry::Open(path))
		{
			BTreeItem* item = new BTreeItem(path.name());
			item->setAsset(entry);
			item->setExpanded(false);
			for (int i = 0; i < node->childCount(); i++)
			{
				BSonNode* childNode = node->child(i);
				BTreeItem* child = createTreeItem(childNode);
				item->addChild(child);
			}
			return item;
		}
	}
	if (node->name() == "file")
	{
		const BString& path = node->text();
		if (BEntry* entry = BEntry::Open(path))
		{
			BTreeItem* item = new BTreeItem(path.name());
			item->setAsset(entry);
			return item;
		}
	}
	return 0;
}

bool MainWindow::openTreeItem(BTreeItem* item)
{
	if (!item)
		return false;
	if (BWidget* widget = _tabWidget->tabOfAsset(item))
	{
		_tabWidget->setCurrent(widget);
		if (item->property("changed"))
		{
			signChanged(widget, true);
		}
	}
	else
	{
		TextEditor* textEdit = new TextEditor();
		textEdit->setAsset(item);
		if (BTextFormat* format = createFormat(item->text().ext()))
		{
			textEdit->setTextFormat(format);
			format->setAsset(textEdit);
		}

		BEntry* entry = item->asset();
		if (item->property("document").empty())
		{
			textEdit->loadFile(entry->path());
		}
		else
		{
			const BString& text = item->property("document");
			textEdit->setText(text);
			textEdit->setTitle(item->text().name());
			textEdit->setIcon(item->icon());
		}
		if (item->property("changed"))
		{
			signChanged(textEdit, true);
		}
		_tabWidget->addTab(textEdit, true);
		_tabWidget->setTabTips(textEdit, entry->path());
		_tabWidget->setCurrent(textEdit);
		connect(textEdit, Signal_PropertyChanged, &MainWindow::slotEditorPropertyChanged);
		connect(textEdit, Signal_Framed, &MainWindow::slotTextEditFramed);
		connect(textEdit, Signal_TextEdited, &MainWindow::slotTextEdited);
	}
	return true;
}
void MainWindow::freshItemIcon(BTreeItem* item)
{
	if (BEntry* entry = item->asset())
	{
		const BStyle* style = this->realStyle();
		BIcon* icon = style->icon(entry->path().ext());
		if (!icon)
			icon = BSystem::EntryIcon(entry->path());
		item->setIcon(icon);
	}
	for (int i = 0; i < item->childCount(); i++)
	{
		BTreeItem* child = item->child(i);
		freshItemIcon(child);
	}
}
void MainWindow::writeSonNode(BTreeItem* item, BSonNode* node)
{
	if (BEntry* entry = item->asset())
	{
		if (entry->attrib() == Attrib_Folder)
		{
			BSonNode* childNode = new BSonNode("folder");
			childNode->setFormat("{\n;\n}\n");
			childNode->setAttrib("path", entry->path());
			for (int i = 0; i < item->childCount(); i++)
			{
				BTreeItem* child = item->child(i);
				writeSonNode(child, childNode);
				node->addChild(childNode);
			}
		}
		else
		{
			BSonNode* childNode = new BSonNode("file");
			childNode->setFormat("}\n");
			childNode->setText(entry->path());
			node->addChild(childNode);
		}
	}
	else
	{
		BSonNode* childNode = new BSonNode("filter");
		childNode->setFormat("}\n");
		childNode->setText(item->text());
		node->addChild(childNode);
	}
}
void MainWindow::updateToolBar()
{
	bool dirty = false;
	bool dirtyAll = false;
	if (BWidget* wdiget = _tabWidget->current())
	{
		if (wdiget->title().endWith('*'))
		{
			dirty = true;
			dirtyAll = true;
		}
		else
		{
			for (int i = 0; i < _tabWidget->tabCount(); i++)
			{
				BWidget* tab = _tabWidget->tab(i);
				if (tab->title().beginWith('*'))
				{
					dirtyAll = true;
					break;
				}
			}
		}
	}
	_saveButton->setEnabled(dirty);
	_saveAllButton->setEnabled(dirtyAll);
}

void MainWindow::slotEditFile(BObject* object, const BValue& value)
{
	const BString& fileName = value;
	openFile(fileName);
}

void MainWindow::slotWorkspaceTitleChanged(BObject* object, const BValue& value)
{
	_workspace->fresh();
}
void MainWindow::slotWorkspaceStyled(BObject* object, const BValue& value)
{
	const BFont* font = _workspace->realFont();
	_workspace->setPerch(Part_Top, font->size() + 6);
}
void MainWindow::slotTreeItemRightClicked(BObject* object, const BValue& value)
{
	BTreeItem* item = value;
	if (!item)
		return;
	const BPoint& point = BCursor::GetPos();
	BPoint pos = point - this->pos();
	_listMenu->setPos(pos);
	_listMenu->popup();
}
void MainWindow::slotTreeItemDoubleClicked(BObject* object, const BValue& value)
{
	if (BTreeItem* item = value)
	{
		BEntry* entry = item->asset();
		if (entry->attrib() == Attrib_File)
		{
			openFile(entry->path());
		}
		else
		{
			int a = 0;
		}
	}
}

void MainWindow::slotTabCurrentChanged(BObject* object, const BValue& value)
{
	updateToolBar();
	_stackListWidget->setAsset(value);
}
void MainWindow::slotEditorPropertyChanged(BObject* object, const BValue& value)
{
	updateToolBar();
}

void MainWindow::slotTabClicked(BObject* object, BValue& value)
{
	BWidget* widget = value;
	if (widget)
	{
		const BString& title = widget->title();
	}
}
void MainWindow::slotTabRightClicked(BObject* object, BValue& value)
{
	BWidget* widget = value;
	const BPoint& point = BCursor::GetPos();
	BPoint pos = point - this->pos();
	_tabMenu->setPos(pos);
	_tabMenu->popup();
	if (BTextEdit* textEdit = value)
	{
		_useStyleMenu->setAsset(value);
		_useStyleMenu->setEnabled(true);
	}
	else
	{
		_useStyleMenu->setAsset(BValue());
		_useStyleMenu->setEnabled(false);
	}
}
void MainWindow::slotTabClosing(BObject* object, BValue& value)
{
	BHtmlWidget* htmlWidget = value;
	if (htmlWidget && htmlWidget->title().first() == '*')
	{
		Button btn = BMessageBox::Question(this, "Close Html", "Do you want close the html document ?");
		if (btn == Button_No)
			value = 0;
	}
}
void MainWindow::slotRemoveButtonClicked(BObject* object, const BValue& value)
{

}
void MainWindow::slotClearButtonClicked(BObject* object, const BValue& value)
{
	_workspace->clearItems();
}
void MainWindow::slotStackListButtonToggled(BButton* button, const BValue& value)
{
	if (value)
	{
		BPoint leftBottom = button->mapTo(this, BPoint(0, button->height()));
		_stackListWidget->setPos(leftBottom);
		_stackListWidget->popup();
	}
	else
	{
		_stackListWidget->hide();
	}
}

void MainWindow::slotOpenPathActionTriggered(BObject* object, const BValue& value)
{
	const BStringList& fileNames = BFileDialog::OpenEntries(0, "Open folder");
	if (fileNames.empty())
		return;
	for (int i = 0; i < fileNames.size(); i++)
	{
		const BString& filePath = fileNames.at(i);
		if (BEntry* entry = BEntry::Open(filePath))
		{
			BTreeItem* topItem = createTreeItem(entry);
			_workspace->addItem(topItem);
			freshItemIcon(topItem);
		}
	}
	signChanged(_workspace, true);
}
void MainWindow::slotOpenFileActionTriggered(BObject* object, const BValue& value)
{
	const BString& fileName = BFileDialog::OpenFile(0, "Open file");
	if (fileName.empty())
		return;
	BEntry* entry = BEntry::Open(fileName);
	BTreeItem* topItem = createTreeItem(entry);
	freshItemIcon(topItem);
	_workspace->addItem(topItem);
	openFile(fileName);
	signChanged(_workspace, true);
}
void MainWindow::slotNewFileActionTriggered(BObject* object, const BValue& value)
{
	const BString& fileName = BFileDialog::SaveFile(0, "Open file");
	if (fileName.empty())
		return;
	BEntry* entry = BEntry::Open(fileName);
	BTreeItem* topItem = new BTreeItem(fileName.name());
	topItem->setAsset(entry);
	_workspace->addItem(topItem);
	freshItemIcon(topItem);
	openFile(fileName);
	signChanged(_workspace, true);
}
void MainWindow::slotSaveFileActionTriggered(BObject* object, const BValue& value)
{
	TextEditor* textEdit = (TextEditor*)_tabWidget->current();
	if (textEdit && textEdit->title().endWith('*'))
	{
		textEdit->saveFile(_tabWidget->tabTips(textEdit));
		textEdit->setProperty("document", textEdit->text());
		signChanged(textEdit, false);
	}
	updateToolBar();
}
void MainWindow::slotSaveAsActionTriggered(BObject* object, const BValue& value)
{

}
void MainWindow::slotSaveAllActionTriggered()
{
	for (int i = 0; i < _tabWidget->tabCount(); i++)
	{
		TextEditor* textEdit = (TextEditor*)_tabWidget->tab(i);
		if (textEdit->title().beginWith('*'))
		{
			textEdit->saveFile(_tabWidget->tabTips(textEdit));
			textEdit->setProperty("document", textEdit->text());
			signChanged(textEdit, false);
		}
	}
	updateToolBar();
}
void MainWindow::slotQuitActionTriggered(BObject* object, const BValue& value)
{
	this->close();
}

void MainWindow::slotUndoActionTriggered(BObject* object, const BValue& value)
{

}
void MainWindow::slotRedoActionTriggered(BObject* object, const BValue& value)
{

}
void MainWindow::slotSearchActionTriggered(BObject* object, const BValue& value)
{
	if (value)
	{
		_searchDialog->popup();
	}
	else
	{
		_searchDialog->hide();
	}
}
void MainWindow::slotCopyActionTriggered(BObject* object, const BValue& value)
{

}
void MainWindow::slotCutActionTriggered(BObject* object, const BValue& value)
{

}
void MainWindow::slotPasteActionTriggered(BObject* object, const BValue& value)
{

}
void MainWindow::slotRemoveActionTriggered(BObject* object, const BValue& value)
{

}

void MainWindow::slotPageMenuTrigger(BObject* object, const BValue& value)
{
	BAction* action = value;
	if (!action)
		return;
	if (action->name() == "action-source")
	{
		BHtmlWidget* html = dynamic_cast<BHtmlWidget*>(_tabWidget->current());
		if (!html)
			return;
		BTextEdit* textEdit = new BTextEdit();
		textEdit->setTitle(html->title() + ".html");
		textEdit->setName(html->name());
		textEdit->setIcon(_textIcon);
		textEdit->setReadOnly(true);
		textEdit->load(html->name());

		_tabWidget->addTab(textEdit, true);
		_tabWidget->setCurrent(textEdit);
		return;
	}
	if (action->name() == "action-tree")
	{
		BHtmlWidget* html = dynamic_cast<BHtmlWidget*>(_tabWidget->current());

	}
}
void MainWindow::slotTableMenuTrigger(BObject* object, const BValue& value)
{
	BAction* action = value;
	if (!action)
		return;
	BHtmlWidget* htmlWidget = dynamic_cast<BHtmlWidget*>(_tabWidget->current());
	if (!htmlWidget)
		return;
	BHtmlItem* item = htmlWidget->selectedItem();
	if (!item)
		return;
	if (item->name() == "td")
	{
		BHtmlItem* table = item->parent("table");
		int row = 0;
		int column = 0;
		int columnCount = 0;
		for (int r = 0; r < table->childCount(); r++)
		{
			BHtmlItem* rowItem = table->child(r);
			if (columnCount < rowItem->childCount())
				columnCount = rowItem->childCount();
			for (int c = 0; c < rowItem->childCount(); c++)
			{
				BHtmlItem* tdItem = rowItem->child(c);
				if (tdItem == item)
				{
					row = r;
					column = c;
					break;
				}
			}
		}
		if (action->name() == "action-add-column")
		{
			for (int r = 0; r < table->childCount(); r++)
			{
				BHtmlItem* rowItem = table->child(r);
				rowItem->addChild(new BHtmlItem("td"));
			}
			return;
		}
		if (action->name() == "action-add-row")
		{
			BHtmlItem* rowItem = new BHtmlItem("tr");
			rowItem->setFormat("\n<");
			for (int c = 0; c < columnCount; c++)
				rowItem->addChild(new BHtmlItem("td"));
			table->addChild(rowItem);
			return;
		}
	}
	if (item->name() == "table")
	{
		int columnCount = 0;
		for (int r = 0; r < item->childCount(); r++)
		{
			BHtmlItem* rowItem = item->child(r);
			if (columnCount < rowItem->childCount())
				columnCount = rowItem->childCount();
		}
	
		if (action->name() == "action-add-row")
		{
			BHtmlItem* rowItem = new BHtmlItem("tr");
			rowItem->setFormat("\n<");
			for (int c = 0; c < columnCount; c++)
				rowItem->addChild(new BHtmlItem("td"));
			item->addChild(rowItem);
			return;
		}
		if (action->name() == "action-add-column")
		{
			for (int i = 0; i < item->childCount(); i++)
			{
				BHtmlItem* rowItem = item->child(i);
				rowItem->addChild(new BHtmlItem("td"));
			}
		}
		return;
	}
}
void MainWindow::slotTabMenuTrigger(BObject* object, const BValue& value)
{
	BAction* action = value;
	if (action->name() == "action-close-tab")
	{
		BWidget* widget = _tabWidget->current();
		_tabWidget->removeTab(widget);
		return;
	}
	if (action->name() == "action-close-all-tab")
	{
		_tabWidget->clearTabs();
		return;
	}
	if (action->name() == "reload-content")
	{
		BWidget* widget = _tabWidget->current();
		this->emit(widget, "reload");
		return;
	}
}

void MainWindow::slotTabCloseTrigger(BObject* object, const BValue& value)
{
	BTextEdit* textEdit = (BTextEdit*)_tabWidget->current();
	const BString& fileName = textEdit->property("fileName");
	if (!BFile::Exist(fileName))
	{
		BString text;
		text << fileName << "\nfile is not exist, do you want to save ?";
		if (Button_Yes == BMessageBox::Question(this, "Question", text))
		{
			BFile::Save(fileName, textEdit->text());
		}
	}
	_tabWidget->removeTab(textEdit);
}
void MainWindow::slotSearchDialogHide(BObject* object, const BValue& value)
{

}
void MainWindow::slotSearchFinished(BObject* object, const BValue& value)
{
	_searchBoard->show();
}
void MainWindow::slotResultItemDoubleClicked(BObject* object, const BValue& value)
{
	BTreeItem* recordItem = value;
	BTreeItem* targetItem = recordItem->asset();
	openTreeItem(targetItem);
	int lineNumber = recordItem->property("line");
	BRange range = recordItem->property("range");

}

void MainWindow::slotMenuAddTrigger(BObject* object, const BValue& value)
{
	BMenu* menu = dynamic_cast<BMenu*>(object);
	if (!menu)
		return;

	BAction* action = value;
	if (!action)
		return;

	BHtmlItemHolder item = new BHtmlItem();
	const BString& text = action->text();
	if (text != "text")
		item->setName(action->text());
	if (text == "p" || text == "div" || (text.size() == 2 && text[0] == 'h'))
		item->setFormat("\n<");


}
void MainWindow::slotMenuPrependTrigger(BObject* object, const BValue& value)
{
	BMenu* menu = dynamic_cast<BMenu*>(object);
	if (!menu)
		return;

	BAction* action = value;
	if (!action)
		return;

	BHtmlItemHolder item = new BHtmlItem();
	const BString& text = action->text();
	if (text != "text")
		item->setName(action->text());
	if (text == "p" || text == "div" || (text.size() == 2 && text[0] == 'h'))
		item->setFormat("\n<");

}
void MainWindow::slotMenuAppendTrigger(BObject* object, const BValue& value)
{
	BMenu* menu = dynamic_cast<BMenu*>(object);
	if (!menu)
		return;

	BAction* action = value;
	if (!action)
		return;

	BHtmlItemHolder item = new BHtmlItem();
	const BString& text = action->text();
	if (text != "text")
		item->setName(action->text());
	if (text == "p" || text == "div" || (text.size() == 2 && text[0] == 'h'))
		item->setFormat("\n<");

}

void MainWindow::slotShowPunctMenuTriggered(BMenu* menu, const BValue& value)
{
	Settings* settings = BApplication::property("settings");
	BAction* action = value;
	if (action->text() == "show-tabs")
		settings->setShowTabs(action->checked());
	if (action->text() == "show-spaces")
		settings->setShowSpaces(action->checked());
	if (action->text() == "show-returns")
		settings->setShowReturns(action->checked());
	if (action->text() == "show-linefeed")
		settings->setShowLinefeeds(action->checked());
	for (int i = 0; i < _tabWidget->tabCount(); i++)
	{
		_tabWidget->tab(i)->fresh();
	}
}
void MainWindow::slotFontActionTriggered(BAction* action, const BValue& value)
{
	if (_fontDialog->execute())
	{
		BFont* font = _fontDialog->font();
		for (int i = 0; i < _tabWidget->tabCount(); i++)
		{
			BWidget* widget = _tabWidget->tab(i);
			widget->setFont(font);
		}
	}
}
void MainWindow::slotToolMenuTriggered(BMenu* menu, const BValue& value)
{
	if (BAction* action = value)
	{
		if (BDialog* dialog = action->asset())
		{
			Settings* settings = BApplication::property("settings");
			dialog->setAsset(settings);
			if (dialog->execute())
			{
				if (settings->isDirty())
					settings->save();
			}
		}
	}
}
void MainWindow::slotStyleMenuTriggered(BMenu* menu, const BValue& value)
{
	if (BAction* action = value)
	{
		BTextEdit* textEdit = menu->asset();
		const BString& ext = action->text();
		if (BTextFormat* format = createFormat(ext.cstr()))
		{
			textEdit->setTextFormat(format);
			format->setAsset(textEdit);
		}
	}
}
void MainWindow::slotMenuStyled(BMenu* menu, const BValue& value)
{
	const BStyle* style = value;
	for (int i = 0; i < menu->count(); i++)
	{
		if (BAction* action = menu->action(i))
		{
			BString text = action->text();
			text.lower();
			action->setTips(style->trans(text));
		}
	}
}

void MainWindow::slotTextEditFramed(BTextEdit* textEdit, const BValue& value)
{
	BPainter painter(textEdit);

	BRange lineRange = textEdit->query("visual-range");
	if (lineRange.valid())
	{
		painter.setColor(Color_Text);
		for (int line = lineRange.min(); line < lineRange.max(); line++)
		{
			const BString& text = textEdit->lineText(line);
			for (auto it = text.begin(); it.valid(); ++it)
			{
				if (it->isSpace())
				{
					painter.setColor(200, 0, 0);
					BRect rect = textEdit->codeRect(line, it.count());
					{
						Settings* settings = BApplication::property("settings");
						if (it == '\t' && settings->showTabs())
						{
							painter.drawLine(rect.leftCenter(), rect.rightCenter());
							int x = rect.right() - 5;
							int y0 = rect.center().y() - 5;
							int y1 = rect.center().y() + 5;
							painter.drawLine(BPoint(x, y0), rect.rightCenter());
							painter.drawLine(BPoint(x, y1), rect.rightCenter());
						}
						if (it == ' ' && settings->showSpaces())
						{
							painter.setPointSmooth(true);
							painter.setPointSize(3);
							painter.drawPoint(rect.center());
							painter.setPointSize(1);
							painter.setPointSmooth(false);
						}
						if (it == '\r' && settings->showReturns())
						{
							//rect.scale(rect.center(), 0.6);
							rect %= 60;
							painter.drawLine(rect.leftCenter(), rect.rightCenter());
							int x = rect.left() + 5;
							int y0 = rect.center().y() - 5;
							int y1 = rect.center().y() + 5;
							painter.drawLine(rect.leftCenter(), BPoint(x, y0));
							painter.drawLine(rect.leftCenter(), BPoint(x, y1));
							painter.drawLine(BPoint(rect.left(), y0), BPoint(rect.left(), y1));
						}
						if (it == '\n' && settings->showLinefeeds())
						{
							rect %= 60;
							painter.drawLine(rect.rightTop(), rect.rightBottom());
							painter.drawLine(rect.leftBottom(), rect.rightBottom());
							int x = rect.left() + 5;
							int y0 = rect.bottom() - 5;
							int y1 = rect.bottom() + 5;
							painter.drawLine(rect.leftBottom(), BPoint(x, y0));
							painter.drawLine(rect.leftBottom(), BPoint(x, y1));
						}
					}
				}
			}
		}
	}

}
void MainWindow::slotTextEdited(BTextEdit* textEdit, const BValue& value)
{
	if (textEdit->title().endWith('*'))
	{

	}
	else
	{
		textEdit->setTitle(textEdit->title() + '*');
	}
}

void MainWindow::closeEvent(const BEvent& event)
{
	if (_saveButton->enabled())
	{
		const BStyle* style = this->realStyle();
		Button button = BMessageBox::Warning("Warning", style->text("warning-close-save"), Button_Save | Button_Cancel);
		if (button == Button_Cancel)
		{
			event.accept(false);
			return;
		}
		if (button == Button_Save)
		{
			_saveButton->click();
		}
	}
	BApplication::exit();
}

void MainWindow::updateEvent(const BEvent& event)
{
	if (!_saveButton->enabled() && _tabWidget->tabCount())
	{
		BWidget* widget = _tabWidget->current();
		if (widget->title().contain('*'))
			_saveButton->setEnabled(true);
	}
	if (!_saveAllButton->enabled() && _saveButton->enabled())
	{
		_saveAllButton->setEnabled(true);
	}
}

void MainWindow::styleEvent(const BEvent& event)
{
	const BStyle* style = event.value();

	_menuBar->flush();

	_htmlIcon = style->icon("html-icon");
	_textIcon = style->icon("text-edit-icon");
	_treeIcon = style->icon("xml-tree-icon");
	_normalImage = style->image("normal");
	_dirtyImage = style->image("dirty");
	_emptyImage = style->image("empty");

	for (int i = 0; i < _tabWidget->tabCount(); i++)
	{
		BWidget* widget = _tabWidget->tab(i);
		if (dynamic_cast<BHtmlWidget*>(widget))
		{
			widget->setIcon(_htmlIcon);
			continue;
		}
		if (dynamic_cast<BTextEdit*>(widget))
		{
			widget->setIcon(_textIcon);
			continue;
		}
	}

	for (int i = 0; i < _workspace->itemCount(); i++)
	{
		BTreeItem* item = _workspace->item(i);
		freshItemIcon(item);
	}

}
